gpt4 book ai didi

python - 在类内、函数内运行 for 循环以使用 exec 创建函数

转载 作者:行者123 更新时间:2023-12-02 12:20:08 25 4
gpt4 key购买 nike

我知道这听起来很复杂,而且可能不可能,但我想我还是会尝试一下。

所以我正在使用 Selenium 进行一些网页抓取,并且任何时候我想在页面上运行一些 jQuery,而不是

driver.execute_script("$('button').parent().click()")

我想整理我的代码,然后就可以了

j('button').parent().click()

我试图通过一个类 j 来实现这一点然后当你有像 parent 这样的函数时它只是返回该类的另一个实例。

在这些示例中,我只是让它打印将要执行的字符串,以便更容易地测试它。按照我的方式,类存在于函数内部。

因此,在这个示例中,当所有类函数都正常定义时,一切正常,但如果取消注释 for循环部分并定义.parent()函数 exec然后你会得到错误 NameError: name 'j' is not defined :

def browser():

class j:

def __init__(self, str):
if str[0] == '$':
self.jq = str
else:
self.jq = f"$('{str}')"

def click(self):
output = f"{self.jq}.click()"
print(output)
return j(output)

def parent(self):
return j(f'{self.jq}.parent()')

# functions = 'parent, next, prev'
# for fn in functions.split(', '):
# exec(
# f"def {fn} (self):\n" +
# f" return j(f'{{self.jq}}.{fn}()')"
# )

j('button').parent().click()

browser()

但是,如果您将所有内容移到 browser 之外函数并运行所有内容,那么这样也不会出现错误,前提是您以任何一种方式定义函数。

我也尝试过做 exec(code, globals())但这只是给了我一个不同的错误消息: AttributeError: 'j' object has no attribute 'parent'

有没有办法用 exec 定义函数以这种方式做我想做的事?

编辑:这是完整的错误消息:

Traceback (most recent call last):
File "C:\Users\Rob\Desktop\site\mysite\py\z.py", line 30, in <module>
browser()
File "C:\Users\Rob\Desktop\site\mysite\py\z.py", line 28, in browser
j('button').parent().click()
File "<string>", line 2, in parent
NameError: name 'j' is not defined

最佳答案

使用setattr以及来自 Dynamic/runtime method creation (code generation) in Python 的示例我做了:

def browser():

class j:

def __init__(self, str):
if str[0] == '$':
self.jq = str
else:
self.jq = f"$('{str}')"

def click(self):
output = f"{self.jq}.click()"
print('click:', output)
return j(output)

def fun(self, name):
return j(f'{self.jq}.{name}()')

def fun2(self, name):
self.jq += f'.{name}()'
return self

# - after class -

functions = 'parent, next, prev'
for fn in functions.split(', '):
#setattr(j, fn, lambda cls, fun=fn: j(f'{cls.jq}.{fun}()'))
#setattr(j, fn, lambda cls, fun=fn: j.fun(cls, fun))
setattr(j, fn, lambda cls, fun=fn: cls.fun(fun))

print('test:', j('button').parent().next().click().fun2('a').fun('b').jq)

browser()

但这并不理想 - 它会创建类似 next = fun("next") 的东西它可以将其运行为 next("x")并添加.x()而不是.next()

<小时/>

我也测试了return self而不是创建新实例 - 而且它也有效。

因为lambda用于 for -loop所以它需要fun=fn正确地从 fn 获取值。如果没有这个,它将从 fn 获取值。当它被执行时,所有函数都会从 fn 获得相同的值- 分配给 fn 的最后一个值循环中。

<小时/>

编辑:而不是直接运行setattrlambda我运行运行 setattr 的函数并使用内部函数而不是 lambda - 这样它就可以创建没有第二个参数的函数,所以现在 .next("x")引发错误。

def browser():

class j:

def __init__(self, str):
if str[0] == '$':
self.jq = str
else:
self.jq = f"$('{str}')"

def click(self):
output = f"{self.jq}.click()"
print('click:', output)
return j(output)

def fun(self, name):
return j(f'{self.jq}.{name}()')

def fun2(self, name):
self.jq += f'.{name}()'
return self

@classmethod
def add_function(cls, name):
def func(cls):
cls.jq += f'.{name}()'
return cls
func.__name__ = name
setattr(j, name, func)

# - after class -

functions = 'parent, next, prev'
for fn in functions.split(', '):
#setattr(j, fn, lambda cls, fun=fn: j(f'{cls.jq}.{fun}()'))
#setattr(j, fn, lambda cls, fun=fn: j.fun(cls, fun))
#setattr(j, fn, lambda cls, fun=fn: cls.fun(fun))
#setattr(j, fn, lambda cls: cls.fun(x))
j.add_function(fn)

item = j('button').parent().next().click().fun2('a').fun('b')
print('test:', item.jq)

j.add_function('other')

item = item.other()
print('test:', item.jq)

item = j('input').other().click()
print('test:', item.jq)

print('name:', j.next.__name__) # gives `next`, without `func.__name__ = name` it gives `func`

browser()
<小时/>

我也测试了__getattr__

def browser():

class j:


def __init__(self, str):
if str[0] == '$':
self.jq = str
else:
self.jq = f"$('{str}')"

def click(self):
return self.fun('click')
#self.jq += f".click()"
#return self

def fun(self, name):
self.jq += f'.{name}()'
return self

functions = ['parent', 'next', 'prev']

#def __getattr__(self, name):
# '''acceptes every name'''
# return lambda: self.fun(name) # I use `lambda` because it needs function to use `()`

#def __getattr__(self, name):
# '''___name__ doesn't change its name in error message and it shows `<lambda>`'''
# a = lambda: self.fun(name)
# a.__name__ = name
# return a

def __getattr__(self, name):
'''acceptes only name from list `functions`'''
if name in self.functions:
return lambda: self.fun(name) # I use `lambda` because it needs function to use `()`
else:
raise AttributeError(f"'j' object has no attribute '{name}'")

#def __getattr__(self, name):
# '''test running without `fun()`'''
# self.jq += f'.{name}()'
# return lambda:self # I use `lambda` because it needs function to use `()`


# - after class -

item = j('button').parent().next().click().fun('a').fun('b')
print('test:', item.jq)

j.functions.append('other')
item = item.other()
print('test:', item.jq)

item = j('input').other().click()
print('test:', item.jq)

#print('name:', j.next.__name__) # doesn't work

print(j('a').tests().jq)

browser()

关于python - 在类内、函数内运行 for 循环以使用 exec 创建函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60332433/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com