Существуют различные альтернативные подходы, которые мы можем использовать для предложения IN в PreparedStatement.
int i = 1;
for(; i <=ids.length; i++){
ps.setInt(i, ids[i-1]);
}
//set null for remaining ones
for(; i<=PARAM_SIZE;i++){
ps.setNull(i, java.sql.Types.INTEGER);
}
Здесь вы можете узнать подробнее об этих альтернативных подходах здесь .
Здесь вы можете посмотреть полный пример:
Introspection может использоваться для разных целей, один из которых представлен в «Dive Into Python» - это просто способ динамически добавлять функциональность (плагин) в ваше приложение.
Динамически я имею в виду без сделать модификацию в основном приложении, чтобы добавить новую функцию.
Взяв пример «Dive Into Python» - простое приложение для извлечения атрибута из файла другого файла - вы можете добавить обработка нового формата файла без внесения изменений в исходное приложение.
Я рекомендую вам закончить книгу. Когда вы читаете, все станет более ясным.
Довольно часто, когда я создаю файл XML из данных, хранящихся в классе, я часто получал ошибки, если атрибут не существовал или имел тип None
. В этом случае моя проблема не зная, что такое имя атрибута, как указано в вашем вопросе, а скорее данные, хранящиеся в этом атрибуте.
class Pet:
def __init__(self):
self.hair = None
self.color = None
Если я использовал hasattr
для сделайте это, он вернет True
, даже если значение атрибута имеет тип None
, и это приведет к ошибке моей команды ElementTree set
.
hasattr(temp, 'hair')
>>True
Если значение атрибута имело тип None
, getattr
также вернет его, что приведет к сбою моей команды ElementTree set
.
c = getattr(temp, 'hair')
type(c)
>> NoneType
Теперь я использую следующий метод, чтобы позаботиться об этих случаях:
def getRealAttr(class_obj, class_attr, default = ''):
temp = getattr(class_obj, class_attr, default)
if temp is None:
temp = default
elif type(temp) != str:
temp = str(temp)
return temp
Это когда и как я использую getattr
.
Я иногда использую getattr(..)
для ленивого инициализации атрибутов вторичной важности непосредственно перед тем, как они используются в коде.
Сравните следующее:
class Graph(object):
def __init__(self):
self.n_calls_to_plot = 0
#...
#A lot of code here
#...
def plot(self):
self.n_calls_to_plot += 1
К этому:
class Graph(object):
def plot(self):
self.n_calls_to_plot = 1 + getattr(self, "n_calls_to_plot", 0)
Преимущество второго способа заключается в том, что n_calls_to_plot
появляется только вокруг места в коде, где он используется. Это полезно для читаемости, потому что (1) вы можете сразу увидеть, какое значение оно начинает при чтении, как оно используется, (2) оно не вводит отвлечение в метод __init__(..)
, который в идеале должен быть о концептуальном состоянии класса, а не некоторый счетчик коммунальных услуг, который используется только одним из методов функции по техническим причинам, таким как оптимизация, и не имеет ничего общего со значением объекта.
Другое использование getattr () при реализации инструкции switch в Python. Он использует оба отражения для получения типа case.
import sys
class SwitchStatement(object):
""" a class to implement switch statement and a way to show how to use gettattr in Pythion"""
def case_1(self):
return "value for case_1"
def case_2(self):
return "value for case_2"
def case_3(self):
return "value for case_3"
def case_4(self):
return "value for case_4"
def case_value(self, case_type=1):
"""This is the main dispatchmethod, that uses gettattr"""
case_method = 'case_' + str(case_type)
# fetch the relevant method name
# Get the method from 'self'. Default to a lambda.
method = getattr(self, case_method, lambda: "Invalid case type")
# Call the method as we return it
return method()
def main(_):
switch = SwitchStatement()
print swtich.case_value(_)
if __name__ == '__main__':
main(int(sys.argv[1]))
Вот быстрый и грязный пример того, как класс может запускать разные версии метода сохранения, в зависимости от того, какую операционную систему он выполняет при использовании getattr()
.
import os
class Log(object):
def __init__(self):
self.os = os.name
def __getattr__(self, name):
""" look for a 'save' attribute, or just
return whatever attribute was specified """
if name == 'save':
try:
# try to dynamically return a save
# method appropriate for the user's system
return getattr(self, self.os)
except:
# bail and try to return
# a default save method
return getattr(self, '_save')
else:
return getattr(self, name)
# each of these methods could have save logic specific to
# the system on which the script is executed
def posix(self): print 'saving on a posix machine'
def nt(self): print 'saving on an nt machine'
def os2(self): print 'saving on an os2 machine'
def ce(self): print 'saving on a ce machine'
def java(self): print 'saving on a java machine'
def riscos(self): print 'saving on a riscos machine'
def _save(self): print 'saving on an unknown operating system'
def which_os(self): print os.name
Теперь давайте использовать этот класс в примере:
logger = Log()
# Now you can do one of two things:
save_func = logger.save
# and execute it, or pass it along
# somewhere else as 1st class:
save_func()
# or you can just call it directly:
logger.save()
# other attributes will hit the else
# statement and still work as expected
logger.which_os()
# getattr
class hithere():
def french(self):
print 'bonjour'
def english(self):
print 'hello'
def german(self):
print 'hallo'
def czech(self):
print 'ahoj'
def noidea(self):
print 'unknown language'
def dispatch(language):
try:
getattr(hithere(),language)()
except:
getattr(hithere(),'noidea')()
# note, do better error handling than this
dispatch('french')
dispatch('english')
dispatch('german')
dispatch('czech')
dispatch('spanish')
Для меня getattr проще всего объяснить следующим образом:
Позволяет вам вызывать методы на основе содержимого строки вместо ввода имени метода.
Например , вы не можете этого сделать:
obj = MyObject()
for x in ['foo', 'bar']:
obj.x()
, поскольку x не относится к типу «builtin», а «str». Однако вы можете это сделать:
obj = MyObject()
for x in ['foo', 'bar']:
getattr(obj, x)()
Он позволяет динамически подключаться к объектам на основе вашего ввода. Я нашел это полезным при работе с пользовательскими объектами и модулями.
Довольно распространенный вариант использования для getattr
- отображение данных в функции.
Например, в веб-среде, такой как Django или Pylons, getattr
упрощает сопоставление URL веб-запроса с функцией, которая будет обрабатывать ее. Если вы посмотрите, например, на капот маршрутизации Pylons, вы увидите, что (по крайней мере, по умолчанию) он разбивает URL-адрес запроса, например:
http://www.example.com/customers/list
на «клиентов» и «клиентов», список". Затем он ищет класс контроллера с именем CustomerController
. Предполагая, что он находит класс, он создает экземпляр класса, а затем использует getattr
для получения своего метода list
. Затем он вызывает этот метод, передавая ему запрос в качестве аргумента.
Как только вы поймете эту идею, становится очень просто расширить функциональность веб-приложения: просто добавьте новые методы в классы контроллера и затем создайте ссылки на своих страницах, которые используют соответствующие URL-адреса для этих методов. Все это стало возможным благодаря getattr
.
Помимо всех удивительных ответов здесь есть способ использовать getattr
, чтобы сэкономить обильные строки кода и сохранить его уютно. Эта мысль возникла после ужасного представления кода, который иногда может быть необходим.
Сценарий
Предположим, что ваша структура каталогов выглядит следующим образом:
- superheroes.py
- properties.py
И , у вас есть функции для получения информации о Thor
, Iron Man
, Doctor Strange
в superheroes.py
. Вы очень хорошо записываете свойства всех из них в properties.py
в компактном dict
, а затем получаете к ним доступ.
properties.py
thor = {
'about': 'Asgardian god of thunder',
'weapon': 'Mjolnir',
'powers': ['invulnerability', 'keen senses', 'vortex breath'], # and many more
}
iron_man = {
'about': 'A wealthy American business magnate, playboy, and ingenious scientist',
'weapon': 'Armor',
'powers': ['intellect', 'armor suit', 'interface with wireless connections', 'money'],
}
doctor_strange = {
'about': ' primary protector of Earth against magical and mystical threats',
'weapon': 'Magic',
'powers': ['magic', 'intellect', 'martial arts'],
}
Теперь, скажем, вы хотите вернуть возможности каждого из них по запросу в superheroes.py
. Таким образом, есть функции, такие как
from .properties import thor, iron_man, doctor_strange
def get_thor_weapon():
return thor['weapon']
def get_iron_man_bio():
return iron_man['about']
def get_thor_powers():
return thor['powers']
... и другие функции, возвращающие разные значения на основе ключей и супергероя.
С помощью getattr
вы можете сделать что-то вроде:
from . import properties
def get_superhero_weapon(hero):
superhero = getattr(properties, hero)
return superhero['weapon']
def get_superhero_powers(hero):
superhero = getattr(properties, hero)
return superhero['powers']
Вы значительно сократили количество строк кода, функций и повторений!
О, и, конечно, если у вас есть плохие имена, такие как properties_of_thor
для переменных , они могут быть сделаны и доступны, просто выполняя
def get_superhero_weapon(hero):
superhero = 'properties_of_{}'.format(hero)
all_properties = getattr(properties, superhero)
return all_properties['weapon']
ПРИМЕЧАНИЕ. Для этой конкретной проблемы могут быть более разумные способы справиться с ситуацией, но идея состоит в том, чтобы дать представление об использовании getattr
в правильных местах, чтобы писать более чистый код.
Объекты в Python могут иметь атрибуты (фактически, каждый объект имеет встроенные атрибуты - атрибуты данных и методы (функции - это значения, т. е. объекты), чтобы работать с ними).
Например у вас есть объект person
, который имеет несколько атрибутов: name
, gender
и т. д.
Доступ к этим атрибутам (будь то методы или объекты данных) обычно записывается: person.name
, person.gender
, person.the_method()
и т. д.
Но что, если вы не знаете имя атрибута в момент написания программы? Например, у вас есть имя атрибута, хранящееся в переменной под названием attr_name
.
, если
attr_name = 'gender'
, вместо записи
gender = person.gender
вы можете write
gender = getattr(person, attr_name)
Некоторая практика:
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
>>> class Person():
... name = 'Victor'
... def say(self, what):
... print(self.name, what)
...
>>> getattr(Person, 'name')
'Victor'
>>> attr_name = 'name'
>>> person = Person()
>>> getattr(person, attr_name)
'Victor'
>>> getattr(person, 'say')('Hello')
Victor Hello
getattr
поднимет AttributeError
, если атрибут с заданным именем не существует в object:
>>> getattr(person, 'age')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'age'
Но вы можете передать значение по умолчанию в качестве третьего аргумента, которое будет возвращено, если такой атрибут не существует:
>>> getattr(person, 'age', 0)
0
Вы можете использовать getattr
вместе с dir
для повторения всех имен атрибутов и получения их значений:
>>> dir(1000)
['__abs__', '__add__', ..., '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
>>> obj = 1000
>>> for attr_name in dir(obj):
... attr_value = getattr(obj, attr_name)
... print(attr_name, attr_value, callable(attr_value))
...
__abs__ <method-wrapper '__abs__' of int object at 0x7f4e927c2f90> True
...
bit_length <built-in method bit_length of int object at 0x7f4e927c2f90> True
...
>>> getattr(1000, 'bit_length')()
10
Практическое использование для этого было бы найти все методы, имена которых начинаются с test
и вызывают их .
Как и в getattr
, имеется setattr
, что позволяет вам установить атрибут объекта, имеющего его имя:
>>> setattr(person, 'name', 'Andrew')
>>> person.name # accessing instance attribute
'Andrew'
>>> Person.name # accessing class attribute
'Victor'
>>>
getattr(..)
следует использовать в двух сценариях: 1. когда имя атрибута является значением внутри переменной (например, getattr(person, some_attr)
) и 2. когда нам нужно использовать третий позиционный аргумент для значения по умолчанию значение (например, getattr(person, 'age', 24)
). Если я вижу сценарий, подобный getattr(person, 'age')
, мне кажется, что он идентичен person.age
, что заставляет меня думать, что person.age
более Pythonic. Это верно?
– wpcarro
24 October 2016 в 22:01