日期: 2021 年 9 月 27 日

Camera setParameters(), getParameters(),unlock()三个方法之间的限制关系

Camera setParameters(), getParameters(),

unlock()

三个方法之间的限制关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Camera mCamera = Camera.open();
// *次调用getParameters()需要在unlock()方法之前否则出现错误
 Camera.Parameters parameters = mCamera.getParameters();
//开启闪光灯
 parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
// *次获取的 parameters 可以在unlock()方法之前直接使用
 mCamera.setParameters(parameters);
 mCamera.unlock();
// 调用unlock()方法之后,如果需要调用setParameters()方法需要重新调用getParameters()获取//parameters否则报错 设置setParameters 失败
 parameters = mCamera.getParameters();
//关闭闪光灯
 parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
// 调用unlock()方法之后,如果需要调用setParameters()方法需要重新调用getParameters()获取//parameters否则报错 设置setParameters 失败
 mCamera.setParameters(parameters);

 

Android录制视频报错setVideoSize called in a invalid state 1

Android录制视频报错setVideoSize called in a invalid state 1

录制视频时想获取手机支持的录制视频的分辨率,使用代码如下:

List<Camera.Size> videoSize = camera.getParameters().getSupportedVideoSizes();
Iterator<Camera.Size> itos = videoSize.iterator();
        while (itos.hasNext()) {
            Camera.Size curSize = itos.next();
            int curSupporSize = curSize.width * curSize.height;
            int fixPictrueSize = setFixPictureWidth * setFixPictureHeight;
            if (curSupporSize > fixPictrueSize) {
                setFixPictureWidth = curSize.width;
                setFixPictureHeight = curSize.height;
            }
        }
mediaRecorder.setVideoSize(setFixPictureWidth,
        setFixPictureHeight);

出现了两次错误,一次是录制视频时调用camera.getParameters()时报parameters is empty,这是由于在camera.unlock()之后调用了该函数,将其在unlock之前获取就ok了。
还有一个错误就是setVideoSize called in a invalid state 1,进入setVideoSize函数中可以发现抛出异常的条件说明

 /**
     * Sets the width and height of the video to be captured.  Must be called
     * after setVideoSource(). Call this after setOutFormat() but before
     * prepare().
     *
     * @param width the width of the video to be captured
     * @param height the height of the video to be captured
     * @throws IllegalStateException if it is called after
     * prepare() or before setOutputFormat()
     */
    public native void setVideoSize(int width, int height)
            throws IllegalStateException;

IllegalStateException if it is called after prepare() or before setOutputFormat()表示如果setVideoSize在prepare() 之后或者setOutputFormat()之前调用的话就会出现该异常,即是说要求setVideoSize函数在prepare()之前以及setOutputFormat()之后调用。
查了下代码,发现我调用setVideoSize竟然是在setOutputFormat()之前,改到setOutputFormat()之后就ok了。

Canvas的效果操作及save()和restore()方法应用

Canvas的效果操作及save()和restore()方法应用

平移、缩放、旋转等操作等于是,我在一个正的画布绘制好图,然后再把画布做旋转、平移、缩放等等的效果。

也就是说,我使用的X、Y坐标还是正常的坐标(没旋转、平移、缩放等之前的坐标)。

 

save()和restore()是用来规定操作的范围的。

如果有save()和restore(),那么平移、缩放、旋转等操作只对save()和restore()作用域之间的代码有效。

 

 

然后我做了代码测试(在onDraw()中画图),如下:

protected void onDraw(Canvas canvas){
//首先定义中心点和半径
int px=getMeasuredWidth()/2;
int py=getMeasuredHeight()/2;

int radius=Math.min(px, py);

canvas.drawCircle(px, py, radius, circlePaint);
canvas.save();//注释save①
canvas.rotate(-bearing, px, py);
//canvas.save();

int textWidth=(int)textPaint.measureText(“W”);
int cardinalX=px-textWidth/2;
int cardinalY=py-radius+textHeight;

//开始绘制刻度和文字
//每15度一个刻度,每45度一个数字,每90度一个方向
for(int i=0; i<24; i++){
canvas.drawLine(px, py-radius, px, py-radius+10, markerPaint);

canvas.save();//注释save②
canvas.translate(0, textHeight);

if(i%6==0){
String dirString=””;
switch(i){
case(0):{
dirString=northString;
int arrowY=2*textHeight;
canvas.drawLine(px, arrowY, px-5, 3*textHeight, markerPaint);
canvas.drawLine(px, arrowY, px+5, 3*textHeight, markerPaint);
break;
}
case(6):dirString=eastString;break;
case(12):dirString=westString;break;
case(18):dirString=southString;break;
}
canvas.drawText(dirString, cardinalX, cardinalY, textPaint);
}
else if(i%3==0){
String angle=String.valueOf(i*15);
float angleTextWidth=textPaint.measureText(angle);

int angleX=(int)(px-angleTextWidth/2);
int angleY=py-radius+textHeight;
canvas.drawText(angle, angleX, angleY, textPaint);
}
canvas.restore();//注释restore②
canvas.rotate(15, px, py);

}
//测试save()和restore()的作用域
canvas.drawText(“Hello world 在restore之前!”, 100, 100, textPaint);
canvas.restore();//注释restore①
canvas.drawText(“Hello world 在restore之后!”, 100, 100, textPaint);
}

//结论:在save②到restore②之间所画的图顶点下移textHeight个像素,restore②之后的代码不受影响

//在save①到restore①之间所画的内容都选择45°,restore①之后的代码不会旋转

//注意save②到restore②也是在save①到restore①作用之内的,所以save②到restore②之间的内容不但顶点下移textHeight个像素,并且旋转

//45度。

Canvas的效果操作及save()和restore()方法应用 - Gobby.X - Gobby.X

android_浅析canvas的save()和restore()方法

android_浅析canvas的save()和restore()方法

  1. <span style=“font-size:18px;”> </span>  
  1. <span style=“font-size:18px;”></span>   

绘图之前,首先需要调整画笔,待画笔调整好之后,再将图像绘制到画布上,这样才可以显示在手机屏幕上!Android 中的画笔是 Paint类,Paint 中包含了很多方法对其属性进行设置,主要常用方法:

setAntiAlias: 设置画笔的锯齿效果。
setColor: 设置画笔颜色
setARGB:  设置画笔的a,r,p,g值。
setAlpha:  设置Alpha值
setTextSize: 设置字体尺寸。
setStyle:  设置画笔风格,空心或者实心。
setStrokeWidth: 设置空心的边框宽度。
getColor:  得到画笔的颜色
getAlpha:  得到画笔的Alpha值。

自定义控件时常常遇到重写View的Ondraw()方法,Ondraw()方法常常设计到save()和restore()这两个方法

,现结合demo简单分析一下这两个方法的作用:

 

1.save():用来保存Canvas的状态,save()方法之后的代码,可以调用Canvas的平移、放缩、旋转、裁剪等操作!

2.restore():用来恢复Canvas之前保存的状态,防止save()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响,通过该方法可以避免连带的影响!

 

通过一个例子说明一下:

例如:我们想在画布上绘制一个向右的三角箭头,当然,我们可以直接绘制,另外,我们也可以先把画布旋转90°,画一个向上的箭头,然后再旋转回来(这种旋转操作对于画圆周上的标记非常有用),*后,我们在右下角绘一个20像素的圆!

 

代码:

  1. <span style=“font-size:18px;”>package com.test.ui;  
  2. import android.R.color;  
  3. import android.content.Context;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.view.View;  
  8. public class GameView extends View  {  
  9.     public final static String TAG = “Example_05_03_GameView”;  
  10.     // 声明Paint对象  
  11.     private Paint mPaint = null;  
  12.     public GameView(Context context) {  
  13.         super(context);  
  14.         mPaint = new Paint();  
  15.     }
  16.     @Override  
  17.     protected void onDraw(Canvas canvas) {  
  18.         super.onDraw(canvas);  
  19.         Paint background=new Paint();  
  20.         Paint line=new Paint();  
  21.         background.setColor(color.darker_gray);
  22.         line.setColor(Color.RED);
  23.         int px = getMeasuredWidth();  
  24.         int py = getMeasuredWidth();  
  25.         // Draw background  
  26.         canvas.drawRect(0, 0, px, py, background);  
  27.         canvas.save();
  28.         canvas.rotate(90, px/2, py/2);                  
  29.          //画一个向上的箭头  
  30.         canvas.drawLine(px / 2, 0, 0, py / 2, line); //左边的斜杠        
  31.         canvas.drawLine(px / 2, 0, px, py / 2, line);//右边的斜杠  
  32.         canvas.drawLine(px / 2, 0, px / 2, py, line);//垂直的竖杠  
  33.         canvas.restore();
  34.         // Draw circle  
  35.         canvas.drawCircle(px – 10, py – 10, 10, line);   
  36.     }
  37. }
  38. </span>

 

MainActivity.Java:

 

  1. <span style=“font-size:18px;”>package com.test.ui;  
  2. import android.app.Activity;  
  3. import android.os.Bundle;  
  4. public class MainActivity extends Activity {  
  5.     private GameView mGameView;  
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_main);
  10.         mGameView = new GameView(this);  
  11.         setContentView(mGameView);
  12.     }
  13. }
  14. </span>

运行结果:

 

%title插图%num

 

如果将 canvas.save()和canvas.restore()注释掉,那么圆点将会随着之前的90旋转跑到了左边,没有达到你预期想要显示在右下角的效果:

 

%title插图%num

 

以上我们很明显看到圆圈位置的明显差异。不进行Canvas的save和restore操作的话,所有的图像都是在画布旋转90°后的画布上绘制的。当执行完onDraw方法,系统自动将画布恢复回来。save和restore操作执行的时机不同,就能绘制不同的图形,save和restore之间,往往是对Canvas的特殊操作!

 

 

Android的4种文件类型Java,class,dex,apk

Android的4种文件类型Java,class,dex,apk

Java文件—–应用程序源文件

Android本身相当一部分都是用java编写而成(基本上架构图里头蓝色的部份都是用Java开发的),android的
应用必须使用java来开发

Class文件——Java编译后的目标文件
不像J2se,java编译成class就可以直接运行,android平台上class文件不能直接在android上运行。 由于Google
使用了自己的Dalvik来运行应用, 所以这里的class也肯定不能在AndroidDalvik的java环境中运行, android
的class文件实际上只是编译过程中的中间目标文件,需要链接成dex文件后才能在dalvik上运行

 

Dex文件—–Android平台上的可执行文件
Android虚拟机Dalvik支持的字节码文件格式Google在新发布的Android平台上使用了自己的Dalvik虚拟机
来定义, 这种虚拟机执行的并非Java字节码, 而是另一种字节码: dex格式的字节码。在编译Java代码之后,
通过Android平台上的工具可以将Java字节码转换成Dex字节码。虽然Google称Dalvik是为了移动设备定
做的,但是业界很多人认为这是为了规避向sun申请Javalicense。这个DalvikVM针对手机程式/CPU做过*
佳化,可以同时执行许多VM而不会占用太多Resource。
Apk文件——-Android上的安装文件
Apk是Android安装包的扩展名,一个Android安装包包含了与某个Android应用程序相关的所有文件。apk
文件将AndroidManifest.xml文件、应用程序代码(.dex文件)、资源文件和其他文件打成一个压缩包。一个工
程只能打进一个.apk文件

Class.forName()的作用与使用总结

Class.forName()的作用与使用总结

1、Class类简介:


Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
Class 没有公共构造方法。Class 对象是在加载类时由Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。

一、如何得到Class的对象呢?有三种方法可以的获取:

1、调用Object类的getClass()方法来得到Class对象,这也是*常见的产生Class对象的方法。例如:
MyObject x;
Class c1 = x.getClass();

2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如:
Class c2=Class.forName(“MyObject”),Employee必须是接口或者类的名字。

3、获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如
Class cl1 = Manager.class;
Class cl2 = int.class;
Class cl3 = Double[].class;
注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。由于历史原因,数组类型的getName方法会返回奇怪的名字。

二、Class类的常用方法

1、getName()

一个Class对象描述了一个特定类的属性,Class类中*常用的方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

2、newInstance()

Class还有一个有用的方法可以为类创建一个实例,这个方法叫做newInstance()。例如:
x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。

3、getClassLoader()

返回该类的类加载器。

4、getComponentType()
返回表示数组组件类型的 Class。

5、getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。

6、isArray()
判定此 Class 对象是否表示一个数组类。

三、Class的一些使用技巧

1、forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如
Object obj = Class.forName(s).newInstance();

2、虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如:
if(e.getClass() == Employee.class)…

2、 Class.forName()方法:


Class.forName:返回与给定的字符串名称相关联接口的Class对象。

Class.forName是一个静态方法,同样可以用来加载类。该方法有两种形式:Class.forName(String name, boolean initialize, ClassLoader loader)和 Class.forName(String className)。*种形式的参数 name表示的是类的全名;initialize表示是否初始化类;loader表示加载时使用的类加载器。第二种形式则相当于设置了参数 initialize的值为 true,loader的值为当前类的类加载器。

static Class<?>

forName(String className)

Returns the Class object associated with the class or interface with the given string name.

static Class<?> forName(String name, boolean initialize, ClassLoader loader)

Returns the Class object associated with the class or interface with the given string name, using the given class loader.

说明:

publicstatic Class<?> forName(String className)

Returns the Class object associated withthe class or interface with the given string name. Invokingthis method is equivalent to:

Class.forName(className,true, currentLoader)

where currentLoader denotes the definingclass loader of the current class.

For example, thefollowing code fragment returns the runtime Class descriptor for theclass named java.lang.Thread:

Class t =Class.forName("java.lang.Thread")

A call to forName("X") causes theclass named X to beinitialized.

Parameters:

className – the fully qualifiedname of the desired class.

Returns:

the Class object for the classwith the specified name.

从官方给出的API文档中可以看出:

Class.forName(className)实际上是调用Class.forName(className,true, this.getClass().getClassLoader())。第二个参数,是指Class被loading后是不是必须被初始化。可以看出,使用Class.forName(className)加载类时则已初始化。

所以Class.forName(className)可以简单的理解为:获得字符串参数中指定的类,并初始化该类。

 

一.首先你要明白在java里面任何class都要装载在虚拟机上才能运行。

1.      forName这句话就是装载类用的(new是根据加载到内存中的类创建一个实例,要分清楚)。

2.      至于什么时候用,可以考虑一下这个问题,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?

A a = (A)Class.forName(“pacage.A”).newInstance();这和 A a =new A();是一样的效果。

3.      jvm在装载类时会执行类的静态代码段,要记住静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再执行这段静态代码了。

4.      Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。

5.      动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象

String str = 用户输入的字符串

Class t = Class.forName(str);

t.newInstance();

 二.在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,*主要有什么区别?

1.它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。

2.那么为什么会有两种创建对象方式?

这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。
Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。例如:

class c = Class.forName(“Example”);

factory = (ExampleInterface)c.newInstance();

其中ExampleInterface是Example的接口,可以写成如下形式:

String className = “Example”;

class c = Class.forName(className);

factory = (ExampleInterface)c.newInstance();

进一步可以写成如下形式:

String className = readfromXMlConfig;//从xml 配置文件中获得字符串

class c = Class.forName(className);

factory = (ExampleInterface)c.newInstance();

上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。
3.从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。  但是使用newInstance()方法的时候,

就必须保证:

1、这个类已经加载;

2、这个类已经连接了。

而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。
现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好

的灵活性,提供给了一种降耦的手段。

三.*后用*简单的描述来区分new关键字和newInstance()方法的区别:

1. newInstance: 弱类型。低效率。只能调用无参构造。
2. new: 强类型。相对高效。能调用任何public构造。

3、应用情景:


情景一:加载数据库驱动的时候

Class.forName的一个很常见的用法是在加载数据库驱动的时候。

如:

  1. Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”);  
  2. Connection con=DriverManager.getConnection(“jdbc:sqlserver://localhost:1433;DatabaseName==JSP”,”jph”,”jph”);      

为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢?

即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?

刚才提到,Class.forName(“”);的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。

而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBCDriver的Driver类的代码都必须类似如下:
public classMyJDBCDriver implements Driver {

static{

DriverManager.registerDriver(new MyJDBCDriver());

}

}

既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

情景二:使用AIDL与电话管理Servic进行通信

Method method =Class.forName(“Android.os.ServiceManager”)

.getMethod(“getService”,String.class);

// 获取远程TELEPHONY_SERVICE的IBinder对象的代理

IBinder binder =(IBinder) method.invoke(null, new Object[] { TELEPHONY_SERVICE});

// 将IBinder对象的代理转换为ITelephony对象

ITelephonytelephony = ITelephony.Stub.asInterface(binder);

// 挂断电话

telephony.endCall();

如何调用一个 function 而不用等待其返回

比如现在有两个 function,一个 fun a,一个 fun b,在 fun a 中需要调用 fun b,但是对 b 的执行结果毫不关心,也不用等待 b 执行完,怎么实现比较合适?
Fun function 调用 等待11 条回复 • 2021-09-25 02:35:01 +08:00
wd 1
wd 2 天前 via iPhone
async 或者线程
kealm 2
kealm 2 天前
“`js
async function b() {
return new Promise((resolve) => setTimeout(resolve, 10000))
}

function a() {
console.time(‘b’)
b()
console.timeEnd(‘b’)
}

async function aa() {
console.time(‘b’)
await b()
console.timeEnd(‘b’)
}
“`
ila 3
ila 2 天前 via Android
celery
Abbeyok 4
Abbeyok 2 天前 via Android
threading.Thread
rootit 5
rootit 2 天前
python 肯定首选 asyncio.create_task() 了,再次 threading 起线程
zhangdeplives 6
zhangdeplives 2 天前
了解一下异步
demonzoo 7
demonzoo 2 天前
就直接在 a 里面调用 b() 就好了啊。。。不要 await b()
IsaacYoung 8
IsaacYoung 2 天前
thread
meiyoumingzi6 9
meiyoumingzi6 2 天前
哈哈哈哈哈哈 我当时刚接触 python 的时候也思考过这个问题

0. 多线程, 把 b 丢进新的线程计算
1. 多进程, 同上
3. 协程 async
4. celcry 等异步框架
5. 换 golang, 无脑 go 就行了 [手动狗头
yianing 10
yianing 2 天前 via Android
golang:go 就完了
dangyuluo 11
dangyuluo 2 天前
这种情况 Async 比多线程要好

使用 pycharm 遇到问题

1
aloxaf 2 天前 ❤️ 2
稍等,我去拿一下水晶球(
zhangdeplives 2
zhangdeplives 2 天前 ❤️ 1
建议移动主题到悬丝诊脉
z740713651 3
z740713651 2 天前
塔罗牌我放家里了
您要不发个面相
麻衣神相我能对着翻
ila 4
ila 2 天前 via Android
掐指一算,明天放假,后来再告诉你
ReferenceE 5
ReferenceE 2 天前 via Android
嗨呀,这个问题我见过,上次就是上面的老哥巴拉巴拉给我算卦算好的
nightwitch 6
nightwitch 2 天前
我抽了一张塔罗牌,占卜的结果是愚者。
ErwinCheung 7
ErwinCheung 2 天前
嗨呀,这个问题我见过,上次就是上面的老哥巴拉巴拉给我算卦算好的
abersheeran 8
abersheeran 2 天前
你等我翻一下易经看看你是什么问题哈。
MiketsuSmasher 9
MiketsuSmasher 2 天前
我刚刚算过一卦,问题应该出在楼主那里
sweetsorrow211 10
sweetsorrow211 1 天前
你等等,等我二大爷托梦了我问问他
cco 11
cco 1 天前
刚烧了一个乌龟壳,显示的卦象是 䝕齛?䬡??,我找专家确认了一下,翻译过来是:这是楼主的锅。

求一个获取 lambda 对象源代码的方法

我先说一下我试过的方法,以及为什么不行:

inspect.getsource:这玩意只能获取*行,比如定义一个多行的 lambda 它也只能拿到*行。并且如果 lambda 前面还有东西,它会一并拿回来,这部满足我的需求,我只想要从 lambda 关键词开始到整个 lambda 结束的定义,是不是原有格式我不在乎,只要完整且不多余就行。
lambda_object.__code__.co_firstlineno:这个同上,实际上 inspect.getsource 就是用这个值去拿的。这个值只能标识*行所在,却不能标识开始的横轴位置以及*后的坐标。
我能想到的解决方式是直接拿到 lambda 对象的字节码,从字节码反编译到 Python 源代码,但是我需要 2.7 和 3.9 、3.10 三个版本同时兼容的……我对字节码反编译不太熟悉,目前找到的都是以文件为单位的反编译,不知道有没有以对象为代码的反编译库。

我想做一个把类似于 User.filter(lambda user: user.age > 18) 这样的语句翻译到 SQL 的玩意。但是卡在了这里。

lambda 字节码 tso urce18 条回复 • 2021-09-26 11:07:16 +08:00
chinvo 1
chinvo 1 天前 ❤️ 1
python 不清楚, C# 里面的 lambda 会被编译成 expression, 就能直接用了.

python 大概也有类似机制?
v2exblog 2
v2exblog 1 天前
同问
hsfzxjy 3
hsfzxjy 1 天前 via Android
我之前实现一个拿 lambda 的 AST 的功能,但这个有个限制就是需要保证前置的 token 是固定的,具体可参考 https://github.com/hsfzxjy/lambdex/blob/master/lambdex/utils/ast.py#L97

比如要求用户写成 def_(lambda: …) ,然后将这个 lambda 对象以及字符串 ‘def_’ 传入这个函数,就可以拿到 AST

可能对你有帮助
hsfzxjy 4
hsfzxjy 1 天前 via Android
@hsfzxjy #3 这个在 3.5-3.10 应该都可以,2.7.没测过
penguinWWY 5
penguinWWY 1 天前
先说这个问题,瞎猜一下

一个方法是通过这个 lambda 反向拿到 module,然后把这个 py 文件编译到 ast 再做遍历

另一个是 PyCodeObject 对象中有一个属性是 co_linetable,这个属性的类型是一个 PyBytesObject,可以看 cpython 中对它的解析方法,应该可以拿到起始行列和终止行列
https://github.com/python/cpython/blob/main/Include/cpython/code.h#L77
penguinWWY 6
penguinWWY 1 天前
@hsfzxjy
@abersheeran

再借楼说下,https://www.v2ex.com/t/804224#reply4
二位有没有兴趣
chenxytw 7
chenxytw 1 天前 ❤️ 1
你的问题本身我不是很了解….但从你要做的事情来看,我在想,是不是没必要用你题目中提出的方法。而是通过实现 User 里 age 的 `__gt__` 之类的魔术方法,在这之中保存一些状态,然后将 Model 本身传给这个 lambda 就能做到你想要的事情了…这应该是*常见的实现类似事情的做法了….当然因为你要做的事情没有详细描述,所以不知道是不是有什么需求导致了你不采用这种方案….
fgwmlhdkkkw 8
fgwmlhdkkkw 1 天前 via Android
@chenxytw Python 的 orm 都是这么做的。
2i2Re2PLMaDnghL 9
2i2Re2PLMaDnghL 1 天前
参考下 PyMacro ?
abersheeran 10
abersheeran 1 天前
@hsfzxjy 你这个思路我也想到过,但是有一个问题我不知道该如何解决,比如同一行出现两个 lambda……

@penguinWWY 在 CPython 运行时用 Python 拿 PyBytesObject 的原始指针做不到的吧?

@chenxytw 这个办法我也想过,问题在于重载运算符不能把 and 、or 、not 运算给重载了……
penguinWWY 11
penguinWWY 1 天前
@abersheeran 当然是使用 C API 辣
O5oz6z3 12
O5oz6z3 1 天前
本质上也许是寻找一个表达式的源码位置:
1. lambda 有多少行?
2. 同一行里有几个 lambda ?
3. 是否嵌套 lambda ?
4. 是否有’lambda’字面字符串?
http://xion .io/post/code/python-get-lambda-code.html
看到这篇文章和#3 楼的实现,想到一个未验证的思路:对 inspect.getsource() 获取的源码进行修剪并编译成 ast,遍历 ast 提取所有 lambda 节点,用 Python3.9 的 ast.unparse() 获取近似的源码,用 co_code 判断源码编译后是否等价。
hsfzxjy 13
hsfzxjy 1 天前 via Android
@penguinWWY co_linetable 应该只存了行号,co_columntable 能拿到列号,但这是 3.10 新加的,兼容性不太好
hsfzxjy 14
hsfzxjy 1 天前 via Android
@abersheeran 我当时的解决方法是强制用户给同一行的 lambda 加不同的前缀,当然这个就比较丑了。同期待更好的方法
abersheeran 15
abersheeran 1 天前
@O5oz6z3 一语惊醒梦中人,只要对比源码编译后的 __code__ 就行了。一行*多也就几个 lambda 。

@hsfzxjy 好家伙,不同前缀有点暴力了
O5oz6z3 16
O5oz6z3 1 天前
@abersheeran #15 我指的是 __code__.co_code 字节码,是从那篇文章中学来的,虽然我也不确定这个字节码比较是否可靠。顺便写了两个 demo 。
简单的情况:
source_text = inspect.getsourcelines(lambda_func)[0][0]
source_ast = ast.parse(source_text)
lambda_node = next((node for node in ast.walk(source_ast) if isinstance(node, ast.Lambda)), None)
lambda_text = ast.unparse(lambda_node)
复杂的情况:
text = ‘lambda’ + inspect.getsource(lambda_func).partition(‘lambda’)[2].rstrip()
while text:
… try:
… … tree = ast.parse(‘({})’.format(text))
… … srcs = [ast.unparse(node) for node in ast.walk(tree) if isinstance(node, ast.Lambda)]
… … break
… except SyntaxError:
… … text = text[:-1]
test = lambda src: compile(src,”,’eval’).co_consts[0].co_code==lambda_func.__code__.co_code
hits = list(filter(test, srcs))
hsfzxjy 17
hsfzxjy 1 天前 ❤️ 1
@O5oz6z3 #16 co_code 不可靠,一个简单的反例

(lambda: print(1)).__code__.co_code == (lambda: sum(1)).__code__.co_code # True

这是因为变量名一类的不存在于字节码中,而是在 __code__.co_names 里
hsfzxjy 18
hsfzxjy 1 天前 ❤️ 2
还有另一个问题是你要考虑 lambda 所在的闭包,看一个例子

def f():
… a = 1
… return lambda: a + 1
a = 1
f().__code__.co_code == (lambda: a + 1).__code__.co_code # False

这两个 lambda 虽然代码相同但是他们字节码不一样。原因是 f() 中的 a 是个 local 变量,读取时会使用 LOAD_DEREF ;而后一个是 global 变量,读取时会使用 LOAD_GLOBAL 。总而言之 corner cases 有很多很多

能否通过代码直接调起 iOS 系统的截屏功能?

App 想做一个截屏的小功能,主要是截屏的时候,还可以有笔刷稍微绘制一下,具体功能如下:
1. 截屏页面,并可拖动设定截屏区域。
2. 有画笔 /橡皮,可以简单编辑 /绘制截图区域。
3. *后,获取到*终图片的 UIImage 数据。

而这些功能正好是系统的截屏功能(除了第 3 点,系统截屏是直接保存文件)。所以我就想有没有办法直接通过代码的方式,来调起 iOS 系统的截屏功能,用户处理完后能够拿到图片数据。
截屏 功能 绘制 iOS10 条回复 • 2021-09-27 14:24:54 +08:00
wipbssldo 1
wipbssldo 13 天前
对 App 的 view 进行截屏就可以了,没办法也不需要调起 iOS 系统的截屏功能
James369 2
James369 13 天前
@wipbssldo 这样虽然可以,但是我就需要额外的开发 笔刷 /橡皮的功能。
qq2511296 3
qq2511296 13 天前
https://share.api.weibo.cn/share/250411462.html?weibo_id=4332707376341309
感觉想起了多年前看到的 jsbox 作者的一条微博 很像是你要的功能,咋实现的不清楚
minamike 4
minamike 13 天前 ❤️ 1
@James369 笔刷 /橡皮可以直接调用系统的 pencilkit 吧
JHExp 5
JHExp 12 天前
找个第三方的编辑图片的库用下好了
cairnechen 6
cairnechen 12 天前
@qq2511296 链接无法访问
MX123 7
MX123 12 天前
苹果好烦人,有些功能系统已经有了,就是不开放给开发者用,比如扫码功能。
Building 8
Building 12 天前 via iPhone
苹果截屏绘图这套框架是开放的,基本上就是把 View 截图成为 Image 再扔给框架就可以了,什么都不用管。
ryh 9
ryh 3 小时 38 分钟前
@MX123 换一个例子吧,不要张口就来了
https://developer.apple.com/documentation/vision/vnbarcodeobservation
MX123 10
MX123 1 小时 39 分钟前
@ryh 不是 Api,是系统相册这类的功能!

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速